home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Atari Compendium
/
The Atari Compendium (Toad Computers) (1994).iso
/
files
/
umich
/
network
/
ka9q
/
nhclb120.zoo
/
slhc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1992-06-18
|
15KB
|
611 lines
/*
* Routines to compress and uncompress tcp packets (for transmission
* over low speed serial lines).
*
* Copyright (c) 1989 Regents of the University of California.
* All rights reserved.
*
* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
*
* Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
* - Initial distribution.
*
*
* modified for KA9Q Internet Software Package by
* Katie Stevens (dkstevens@ucdavis.edu)
* University of California, Davis
* Computing Services
* - 01-31-90 initial adaptation (from 1.19)
* PPP.05 02-15-90 [ks]
* PPP.08 05-02-90 [ks] use PPP protocol field to signal compression
* PPP.15 09-90 [ks] improve mbuf handling
* PPP.16 11-02 [karn] substantially rewritten to use NOS facilities
*
* - Feb 1991 Bill_Simpson@um.cc.umich.edu
* variable number of conversation slots
* allow zero or one slots
* separate routines
* status display
*/
#if !defined(MWC)
#include <memory.h>
#else
int memcpy(),memcmp();
void memset();
#endif
#include "global.h"
#include "mbuf.h"
#include "timer.h"
#include "internet.h"
#include "netuser.h"
#include "ip.h"
#include "tcp.h"
#include "slhc.h"
struct mbuf *htonip();
struct mbuf *htontcp();
#define __ARGS(x) x
extern int last_retran;
#ifndef ATARI_ST
static char *encode __ARGS((char *cp,int n));
static long decode __ARGS((struct mbuf **bpp));
#else
static char *encode();
static long decode();
#endif
#define PULLCHAR(bpp)\
((bpp) != NULL && (*bpp) != NULLBUF && (*bpp)->cnt > 1 ? \
((*bpp)->cnt--,(unsigned char)*(*bpp)->data++) : pullchar(bpp))
/* Initialize compression data structure
* slots must be in range 0 to 255 (zero meaning no compression)
*/
struct slcompress *
slhc_init( rslots, tslots )
int rslots;
int tslots;
{
register int16 i;
register struct cstate *ts;
struct slcompress *comp;
comp = (struct slcompress *)calloc(1, sizeof(struct slcompress) );
if (! comp)
return NULL;
if ( rslots > 0 && rslots < 256 ) {
comp->rstate =
(struct cstate *)calloc(rslots, sizeof(struct cstate) );
if (! comp->rstate)
return NULL;
comp->rslot_limit = rslots - 1;
}
if ( tslots > 0 && tslots < 256 ) {
comp->tstate =
(struct cstate *)calloc(tslots, sizeof(struct cstate) );
if (! comp->tstate)
return NULL;
comp->tslot_limit = tslots - 1;
}
comp->xmit_oldest = 0;
comp->xmit_current = 255;
comp->recv_current = 255;
/*
* don't accept any packets with implicit index until we get
* one with an explicit index. Otherwise the uncompress code
* will try to use connection 255, which is almost certainly
* out of range
*/
comp->flags |= SLF_TOSS;
if ( tslots > 0 ) {
ts = comp->tstate;
for(i = comp->tslot_limit; i > 0; --i){
ts[i].this = i;
ts[i].next = &(ts[i - 1]);
}
ts[0].next = &(ts[comp->tslot_limit]);
ts[0].this = 0;
}
return comp;
}
/* Free a compression data structure */
void
slhc_free(comp)
struct slcompress *comp;
{
if ( comp == NULLSLCOMPR )
return;
if ( comp->rstate != NULLSLSTATE )
free( comp->rstate );
if ( comp->tstate != NULLSLSTATE )
free( comp->tstate );
free( comp );
}
/* Encode a number */
static char *
encode(cp,n)
register char *cp;
int n;
{
if(n >= 256 || n == 0){
*cp++ = 0;
cp = put16(cp,n);
} else {
*cp++ = n;
}
return cp;
}
/* Decode a number */
static long
decode(bpp)
struct mbuf **bpp;
{
register int x;
x = PULLCHAR(bpp);
if(x == 0){
return pull16(bpp) & 0xffff; /* pull16 returns -1 on error */
} else {
return x & 0xff; /* -1 if PULLCHAR returned error */
}
}
int
slhc_compress(comp, bpp, compress_cid)
struct slcompress *comp;
struct mbuf **bpp;
int compress_cid;
{
register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]);
register struct cstate *lcs = ocs;
register struct cstate *cs = lcs->next;
register int16 hlen;
register struct tcp *oth;
register unsigned long deltaS, deltaA;
register int16 changes = 0;
char new_seq[16];
register char *cp = new_seq;
struct mbuf *bp;
struct tcp th;
struct ip iph;
/* Extract IP header */
hlen = ntohip(&iph,bpp);
/* Bail if this packet isn't TCP, or is an IP fragment */
if(iph.protocol != TCP_PTCL || (iph.fl_offs & F_OFFSET) != 0 ||
(iph.fl_offs & MF)){
/* Send as regular IP */
if(iph.protocol != TCP_PTCL)
comp->sls_o_nontcp++;
else
comp->sls_o_tcp++;
*bpp = htonip(&iph,*bpp,iph.checksum);
return SL_TYPE_IP;
}
/* Extract TCP header */
hlen += ntohtcp(&th,bpp);
/* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or
* some other control bit is set).
*/
if((th.flags & SYN) || (th.flags & FIN) || (th.flags & RST) ||
! (th.flags & ACK)){
/* TCP connection stuff; send as regular IP */
comp->sls_o_tcp++;
*bpp = htontcp(&th,*bpp,NULL);
*bpp = htonip(&iph,*bpp,iph.checksum);
return SL_TYPE_IP;
}
/*
* Packet is compressible -- we're going to send either a
* COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way,
* we need to locate (or create) the connection state.
*
* States are kept in a circularly linked list with
* xmit_oldest pointing to the end of the list. The
* list is kept in lru order by moving a state to the
* head of the list whenever it is referenced. Since
* the list is short and, empirically, the connection
* we want is almost always near the front, we locate
* states via linear search. If we don't find a state
* for the datagram, the oldest state is (re-)used.
*/
for ( ; ; ) {
if( iph.source == cs->cs_ip.source
&& iph.dest == cs->cs_ip.dest
&& th.source == cs->cs_tcp.source
&& th.dest == cs->cs_tcp.dest)
goto found;
/* if current equal oldest, at end of list */
if ( cs == ocs )
break;
lcs = cs;
cs = cs->next;
comp->sls_o_searches++;
};
/*
* Didn't find it -- re-use oldest cstate. Send an
* uncompressed packet that tells the other side what
* connection number we're using for this conversation.
*
* Note that since the state list is circular, the oldest
* state points to the newest and we only need to set
* xmit_oldest to update the lru linkage.
*/
comp->sls_o_misses++;
comp->xmit_oldest = lcs->this;
goto uncompressed;
found:
/*
* Found it -- move to the front on the connection list.
*/
if(lcs == ocs) {
/* found at most recently used */
} else if (cs == ocs) {
/* found at least recently used */
comp->xmit_oldest = lcs->this;
} else {
/* more than 2 elements */
lcs->next = cs->next;
cs->next = ocs->next;
ocs->next = cs;
}
/*
* Make sure that only what we expect to change changed.
* Check the following:
* IP protocol version, header length & type of service.
* The "Don't fragment" bit.
* The time-to-live field.
* The TCP header length.
* IP options, if any.
* TCP options, if any.
* If any of these things are different between the previous &
* current datagram, we send the current datagram `uncompressed'.
*/
oth = &cs->cs_tcp;
if(last_retran
|| iph.version != cs->cs_ip.version || iph.optlen != cs->cs_ip.optlen
|| iph.tos != cs->cs_ip.tos
|| (iph.fl_offs & DF) != (cs->cs_ip.fl_offs & DF)
|| iph.ttl != cs->cs_ip.ttl
|| th.optlen != cs->cs_tcp.optlen
|| (iph.optlen > 0 && memcmp(iph.options,cs->cs_ip.options,iph.optlen) != 0)
|| (th.optlen > 0 && memcmp(th.options,cs->cs_tcp.options,th.optlen) != 0)){
last_retran = 0;
goto uncompressed;
}
/*
* Figure out which of the changing fields changed. The
* receiver expects changes in the order: urgent, window,
* ack, seq (the order minimize